﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;
using Dispatcher.ViewModels.Base;

namespace Dispatcher.Extensions
{
    /// <summary>
    /// Extension methods.
    /// </summary>
    internal static class CommonExtensions
    {
        /// <summary>
        /// Random number generator.
        /// </summary>
        private static readonly Random Random = new Random();

        /// <summary>
        /// Adds the range.
        /// </summary>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="addItems">The add items.</param>
        public static void AddRange<TItem>(this EntityCollection<TItem> collection, IEnumerable<TItem> addItems) where TItem : class
        {
            foreach (var addItem in addItems)
            {
                collection.Add(addItem);
            }
        }

        /// <summary>
        /// Adds the objects.
        /// </summary>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="collection">The collection.</param>
        /// <param name="addItems">The add items.</param>
        public static void AddObjects<TItem>(this ObjectSet<TItem> collection, IEnumerable<TItem> addItems) where TItem : class
        {
            foreach (var addItem in addItems)
            {
                collection.AddObject(addItem);
            }
        }

        /// <summary>
        /// Gets the random item.
        /// </summary>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="items">The items.</param>
        /// <returns>Random item.</returns>
        public static TItem GetRandomItem<TItem>(this IEnumerable<TItem> items)
        {
            var itemList = items.ToList();
            if (itemList.Count == 0)
            {
                return default(TItem);
            }

            var i = Random.Next(itemList.Count);
            return itemList[i];
        }

        /// <summary>
        /// Binds the specified model.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="model">The model.</param>
        public static void Bind(this Control view, ViewModelBase model)
        {
            view.DataContext = model;
            view.CommandBindings.AddRange(model.CommandBindings);
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <param name="property">The property.</param>
        /// <param name="obj">The obj.</param>
        /// <returns>Value of property.</returns>
        public static object GetValue(this PropertyInfo property, object obj)
        {
            return property == null ? null : property.GetValue(obj, BindingFlags.GetProperty, null, null, null);
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <typeparam name="TValue">The type of the property.</typeparam>
        /// <param name="property">The property.</param>
        /// <param name="obj">The obj.</param>
        /// <returns>Value of property.</returns>
        public static TValue GetValue<TValue>(this PropertyInfo property, object obj) where TValue : class
        {
            return property.GetValue(obj, BindingFlags.GetProperty, null, null, null) as TValue;
        }

        /// <summary>
        /// Adds the range.
        /// </summary>
        /// <typeparam name="TItem">The type of the item.</typeparam>
        /// <param name="observableCollection">The observable collection.</param>
        /// <param name="items">The items.</param>
        public static void AddRange<TItem>(this ObservableCollection<TItem> observableCollection, IEnumerable<TItem> items)
        {
            if (items == null)
            {
                return;
            }

            foreach (var item in items)
            {
                observableCollection.Add(item);
            }
        }
    }
}
